#include "windowwidget.h"
#include "ui_windowwidget.h"

#include <iostream>
#include <fstream>

/*
 Problems:
    -camera movement incomplete
    -fle dialog not appearing on top of full screen mode
    -switch to maximized messed up menu spacing

 menu:
    -create: goto blank map
    -load: open window, ask for file, load in and go to map mode, and message "Loaded"
    -save: save initial config of current map, goto map mode, and message "Saved"
    -run: go to 3d mode and message if no scenario contents...
    -speed: change running speed of scenario
    -map: goto overhead view, and pause?
 */
/*
 controls:
    -menu
        -enter: save, load, create, run, map
    -3d mode:
        -esc: menu
    -map mode:
        -esc: menu
 */

windowWidget::windowWidget(QWidget *parent) :
    QGLWidget(parent),
    ui(new Ui::windowWidget)
{
    ui->setupUi(this);

    timer.setSingleShot(false);
    connect(&timer, SIGNAL(timeout()), this, SLOT(animate()));
    timer.start(33);
}

windowWidget::~windowWidget()
{
    delete ui;
}

void windowWidget::mousePressEvent(QMouseEvent *event){
    QCursor::setPos(0,0);
}

void windowWidget::mouseMoveEvent(QMouseEvent *event){

}

void windowWidget::mouseReleaseEvent(QMouseEvent *event){

}

void windowWidget::keyPressEvent(QKeyEvent *event){
    if(playMode==0){//menu mode
        switch(event->key()){
        case Qt::Key_Escape:
            exit(1);
            break;
        case Qt::Key_Down:
            //increment menu postion
            if(menuSel<5){
                menuSel++;
            }
            else{
                menuSel=0;
            }
            break;
        case Qt::Key_Up:
            //decrement menu position
            if(menuSel>0){
                menuSel--;
            }
            else{
                menuSel=5;
            }
            break;
        case Qt::Key_Right:
            //speed only
            if(menuSel==5){
                if(speedChoice<3){
                    speedChoice++;
                }
                else{
                    speedChoice=0;
                }
            }
            break;
        case Qt::Key_Left:
            //speed only
            if(menuSel==5){
                if(speedChoice>0){
                    speedChoice--;
                }
                else{
                    speedChoice=3;
                }
            }
            break;
        case Qt::Key_Return:
            if(menuSel==0){//create
                //clear current data
                //go to map mode
                playMode=2;
            }
            else if(menuSel==1){//load
                //open file dialog, ask for file name
                //load in all file content
                loadScenario();
                //go to map mode for adjustments, show loaded text
                playMode=2;
            }
            else if(menuSel==2){//save
                //open file dialog, get save file name
                //save all scenario...
                saveScenario();
                //go to map mode again, show saved text
                playMode=2;
            }
            else if(menuSel==3){//run
                //go to 3d mode and unpause
                playMode=1;
            }
            else if(menuSel==4){//map
                //go to the map and pause
                playMode=2;
            }
            else{// if(menuSel==5){//speed
                //nothing, speed not enterable...
            }
            break;
        default:
            break;
        }
    }
    else if(playMode==1){//active mode
        switch(event->key()){
        case Qt::Key_Escape://goto menu
            playMode=0;
            break;
        case Qt::Key_Up:
	  std::cout << "Moving forward." << std::endl;
            myCamera.moveForward();
            break;
        case Qt::Key_Left:
	  std::cout << "Moving left." << std::endl;
            myCamera.moveLeft();
            break;
        case Qt::Key_Right:
	  std::cout << "Moving right." << std::endl;
            myCamera.moveRight();
            break;
        case Qt::Key_Down:
	  std::cout << "Moving back." << std::endl;
            myCamera.moveBack();
            break;
        case Qt::Key_PageUp:
	  std::cout << "Moving up." << std::endl;
            myCamera.moveUp();
            break;
        case Qt::Key_PageDown:
	  std::cout << "Moving down." << std::endl;
            myCamera.moveDown();
            break;
	case Qt::Key_R:
	  std::cout << "Toggling rotation." << std::endl;
	  myCamera.toggleRotating();
	  break;
        default:
	  std::cout << "Nothing going on..." << std::endl;
            break;
        }
    }
    else{//map mode
        switch(event->key()){
        case Qt::Key_Escape://goto menu
            playMode=0;
            break;
        case Qt::Key_Up:
	  std::cout << "Should be moving forward." << std::endl;
            myCamera.moveForward();
            break;
        case Qt::Key_Left:
	  std::cout << "should be moving left." << std::endl;
            myCamera.moveLeft();
            break;
        case Qt::Key_Right:
	  std::cout << "Should be moving right. " << std::endl;
            myCamera.moveRight();
            break;
        case Qt::Key_Down:
	  std::cout << "Should be moving back. " << std::endl;
            myCamera.moveBack();
            break;
        case Qt::Key_PageUp:
            myCamera.moveUp();
            break;
        case Qt::Key_PageDown:
            myCamera.moveDown();
            break;
	case Qt::Key_R:
	  std::cout << "Toggling rotating." << std::endl;
	  myCamera.toggleRotating();
	  break;
        default:
            break;
        }
    }
    updateGL();
}

void windowWidget::initializeGL(){
    //Initialize variables of class, as in constructor
    //showFullScreen();
    showMaximized();
    //set menu stuff
    playMode=0;//in Menu
    worldLoaded=0;
    subMenu=0;//no sub menu
    menuSel=0;//first item
    initMenuX=menuX=width()/2;
    initMenuY=menuY=150;
    yInc=60;
    speedChoice=0;

    //load meshes
    blackjack::MeshLoader mLoader;
    blackjack::TerrainLoader tLoader;

    ///Terrain load here(sort of)
    terrain = new blackjack::Terrain();
    //tLoader.loadFromPGM(t, "ireland.pgm");//move to Load function

    /////////////////////////////

    glClearColor(0.0, 0.0, 0.0, 1.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glEnable(GL_DEPTH_TEST);

    float w = (float)width();
    float h = (float)height();

    gluPerspective(45.0, w/h, 1.0, 10000.0);

    //lighting
    glEnable(GL_COLOR_MATERIAL);
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    //lighting cont
    sceneLights.turnOnLights();

    //set up camera
    myCamera.setUp();
}

void windowWidget::paintGL(){
    glClearColor(0.0,0.0,0.0,1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    //creat fonts...can't do in header...
    QFont serifFont("Times", 30);//create font 1 //ar destine, papyrus
    QFont serifFont2("ar destine", 50, QFont::Bold);//font 2
    if(playMode==0){//menu
        glColor3f(0.2,1.0,0.0);
        renderText(menuX-200,90,"Ship Sim", serifFont2);
        if(menuSel==0){//create
            glColor3f(0.2,1.0,0.0);
        }
        else{
            glColor3f(0.0,0.5,0.0);
        }
        renderText(menuX-100,menuY,"Create", serifFont);
        if(menuSel==1){//load
            glColor3f(0.2,1.0,0.0);
        }
        else{
            glColor3f(0.0,0.5,0.0);
        }
        renderText(menuX-100,menuY+yInc*1,"Load", serifFont);
        if(menuSel==2){//save
            glColor3f(0.2,1.0,0.0);
        }
        else{
            glColor3f(0.0,0.5,0.0);
        }
        renderText(menuX-100,menuY+yInc*2,"Save", serifFont);
        if(menuSel==3){//run
            glColor3f(0.2,1.0,0.0);
        }
        else{
            glColor3f(0.0,0.5,0.0);
        }
        renderText(menuX-100,menuY+yInc*3,"Run", serifFont);
        if(menuSel==4){//map
            glColor3f(0.2,1.0,0.0);
        }
        else{
            glColor3f(0.0,0.5,0.0);
        }
        renderText(menuX-100,menuY+yInc*4,"Map", serifFont);
        if(menuSel==5){//speed
            glColor3f(0.2,1.0,0.0);
        }
        else{
            glColor3f(0.0,0.5,0.0);
        }
        if(speedChoice==0){
            renderText(menuX-100,menuY+yInc*5,"< Speed: 1 >", serifFont);
        }
        else if(speedChoice==1){
            renderText(menuX-100,menuY+yInc*5,"< Speed: 2 >", serifFont);
        }
        else if(speedChoice==2){
            renderText(menuX-100,menuY+yInc*5,"< Speed: 3 >", serifFont);
        }
        else{
            renderText(menuX-100,menuY+yInc*5,"< Speed: 4 >", serifFont);
        }
    }
    else if(playMode==1){//active

      glClearColor(135.0/256.0, 206.0/256.0, 250.0/256.0, 1.0);

      if(worldLoaded==1){
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	// apply camera transform
	myCamera.applyTransform();

	// draw terrain
	terrain->drawTerrain();
        glColor3f(0.0,0.0,1.0);
        glBegin(GL_POLYGON);
          glVertex3f(2000.0, 0, 2000.0);
          glVertex3f(-2000.0, 0, 2000.0);
          glVertex3f(-2000.0, 0, -2000.0);
          glVertex3f(2000.0, 0, -2000.0);
        glEnd();

	// draw the boats
	for (int i = 0; i < 10; ++i) {
	  glPushMatrix();
          boat temp;
          temp=fleet.front();
            //iterate through fleet, draw each at current position...
          glTranslatef(temp.current[0], 0, temp.current[1]);
            //draw
          //temp.obj->draw();
	  glPopMatrix();
	}
	
      } else {
	renderText(menuX-100,menuY,"No scenario loaded", serifFont);
      }

    }
    else{//map
        if(worldLoaded==1){

          glClearColor(135.0/256.0, 206.0/256.0, 250.0/256.0, 1.0);
	  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	  
	  glMatrixMode(GL_MODELVIEW);
	  glLoadIdentity();

	  // apply camera transform
	  myCamera.applyTransform();

	  // draw terrain
	  terrain->drawTerrain();
          glColor3f(0.0,0.0,1.0);
          glBegin(GL_POLYGON);
            glVertex3f(2000.0, 0, 2000.0);
            glVertex3f(-2000.0, 0, 2000.0);
            glVertex3f(-2000.0, 0, -2000.0);
            glVertex3f(2000.0, 0, -2000.0);
          glEnd();

          // draw the boats
          for (int i = 0; i < fleet.size(); ++i) {
            glPushMatrix();
            boat temp;
            temp=fleet[i];
              //iterate through fleet, draw each at current position...
            glTranslatef(fleet[i].current[0], 0, fleet[i].current[1]);
              //draw
            if (fleet[i].danger) {
                fleet[i].obj->color[0] = 1.0;
                fleet[i].obj->color[1] = 0.0;
                fleet[i].obj->color[2] = 0.0;
            } else {
                fleet[i].obj->color[0] = 0.2;
                fleet[i].obj->color[1] = 0.2;
                fleet[i].obj->color[2] = 0.2;
            }

            if (!fleet[i].colliding)
              fleet[i].obj->draw();
            glPopMatrix();
          }
        }
        else{
            glColor3f(1.0,1.0,1.0);
            renderText(menuX-100,menuY,"No scenario loaded", serifFont);
        }

    }

}

void windowWidget::resizeGL(int width, int height){
    //showFullScreen();
    showMaximized();
    glViewport(0, 0, width, height);
}

void windowWidget::setupViewport(int width, int height){
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(45, (float)width/(float)height, 1.0, 400.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void windowWidget::checkCollisions(){

}

void windowWidget::resetGame(){

}

void windowWidget::autoPlay(){

}

void windowWidget::loadScenario(){//-load //function: file dialog
    QString fileName = QFileDialog::getOpenFileName(this,
         tr("Open Scenario"), "scenarios/", tr("Scenario Files (*.scn)"));//check if canceled?
    std::string file_name = fileName.toStdString();

    std::cout << "Opening: " << file_name << std::endl;
    blackjack::MeshLoader mLoader;

    std::string currentLine;
    int init[2];
    boat temp;
    size_t first, last;
    std::vector<std::string> v;
    std::ifstream file(file_name.c_str());

    // load terrain
    getline(file, currentLine);
    std::cout << "Loading terrain model: " << currentLine << std::endl;
    blackjack::TerrainLoader tl;
    tl.loadFromPGM(terrain, currentLine);
    worldLoaded = 1;

    while (getline(file, currentLine)) {//getline(file, currentLine)
      // load i-th model
      // set mesh
            //load model name string (*.obj)
      first = currentLine.find(" ");
      temp.mesh = currentLine.substr(0,first);
      //load mesh into boat obj
        mLoader.loadFromFile(temp.obj, temp.mesh);
        temp.obj->color[0]=0.2;
        temp.obj->color[1]=0.2;
        temp.obj->color[2]=0.2;
        //qDebug()<<"HI";
        //qDebug()<<QString::fromStdString(temp.obj->toString());
      //qDebug()<<QString::fromStdString(temp.mesh);
      // set name/number
            //load ship name
      last = currentLine.find(" ",first+1);//have first space and next
      //qDebug()<<int(first)<<' '<<int(last);
      temp.name = currentLine.substr(first, last-first);
      //qDebug()<<QString::fromStdString(temp.name);
      //qDebug()<<int(first)<<' '<<int(last);
      // set position
            //get coordnates (2d)
      first = currentLine.find("(");
      last = currentLine.find(",",first);
      qDebug() << currentLine.substr(first+1, last-first).c_str();
      init[0] = atoi(currentLine.substr(first+1,last-first).c_str());
      first = last;
      last = currentLine.find(")",first);
      qDebug() << currentLine.substr(first, last-first).c_str();
      init[1] = atoi(currentLine.substr(first+1,last-first).c_str());
      temp.positions.push_back(init);
      temp.current[0]=init[0];
      temp.current[1]=init[1];
      qDebug()<<"currentPos"<<init[0]<<','<<init[1];
      // set waypoints
      size_t fin = currentLine.find_last_of(")");
      //qDebug()<<int(fin);
      while(last!=fin){
                first = currentLine.find("(", last);
                last = currentLine.find(",",first);
                if(last!=size_t(-1)){
                    init[0] = atoi(currentLine.substr(first,last-first).c_str());
                    first = last;
                    last = currentLine.find(")",first);
                    init[1] = atoi(currentLine.substr(first,last-first).c_str());
                    temp.positions.push_back(init);
                    //qDebug()<<"currentPos"<<init[0]<<','<<init[1];
                }
            }
      //add boat to fleet
      fleet.push_back(temp);
    qDebug() << "Pushed a ship";
  }
}

void windowWidget::saveScenario(){//-save //function: file dialog
    QString fileName = QFileDialog::getSaveFileName(this,
         tr("Save Scenario"), "scenarios/", tr("Scenario Files (*.scn)"));//check if canceled?
    std::string file_name = fileName.toStdString();

    std::cout << "Opening: " << file_name << std::endl;

    std::ofstream file(file_name.c_str());
    //store terrain file name
    file<<terrain->name<<endl;
    //store boats: mesh, name, positions

}

void windowWidget::animate() {
  
  // check for collisions/update physics
    for (int i = 0; i < fleet.size(); ++i) {
        for (int j = 0; j < fleet.size(); ++j) {
            if(i == j)
                continue;
            float x_diff = fleet[i].current[0] - fleet[j].current[0];
            float z_diff = fleet[i].current[1] - fleet[j].current[1];

            if (x_diff*x_diff + z_diff*z_diff < 50) {
                fleet[i].danger = true;
            }

            if (x_diff*x_diff + z_diff*z_diff < 16) {

                qDebug() << "Collision! Between " << i << " " << j;
                fleet[i].setColliding(true);
                fleet[j].setColliding(true);
            }
        }
    }

    // check for boat/land collisions
    for (int i = 0; i < fleet.size(); ++i) {
        int x = fleet[i].current[0];
        int z = fleet[i].current[1];
        if (terrain->data[x * terrain->height + z] > 3 &&
            terrain->data[x * terrain->height + z] < 256) {
            qDebug() << "Beached!" << terrain->data[x * terrain->height + z];
        }
    }

  // update positions
    int mult;
    for (int i = 0; i < fleet.size(); ++i) {
        if (i % 2 == 0) {
          mult = 1;
        } else {
            mult = -1;
        }
     fleet[i].current[0] +=  mult * 0.05;
     fleet[i].current[1] += mult * 0.05;
    }

  // draw the world
  updateGL();

}
